import * as THREE from 'three'
import { mergeBufferGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils.js'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
import { Base, OrbitControls, State, AssetsManager, Plane, getBoundingBox } from '@/libs/mini3d'
import { Grid } from './components/grid'
import { BaseMap } from './components/map'
import { Line } from './components/line'
import { Lights } from './components/lights'
import { Wall } from './components/wall'
import { Particles } from './components/particles'
import { UpShader } from './shader/upShader/index'
import { SpreadShader } from './shader/spreadShader/index'
import { GradientShader } from './shader/gradientShader/index'
import _ from 'lodash'
import { Label2d } from '@/libs/mini3d/extra/label2d'
import config from '@/config'
import { geoProjection, transfromGeoJSON, center, exportGLTF, exportImage } from './utils'
import { random } from './utils/utils'
const assets = [
  { name: 'china', type: 'file', path: './data/中华人民共和国.json' },
  { name: 'province', type: 'file', path: './data/浙江省.json' },
  { name: 'city', type: 'file', path: './data/金华市.json' },
  { name: 'rotationBorder1', type: 'texture', path: './data/rotationBorder1.png' },
  { name: 'rotationBorder2', type: 'texture', path: './data/rotationBorder2.png' },
]

export class Map3d extends Base {
  constructor(el) {
    super(el)
    localStorage.setItem('center', JSON.stringify(config.center))
    this.camera.lookAt(...center(), 0)
    this.camera.up.set(0, 0, 1)
    this.camera.position.set(-6.968712521495332, -15.909690758173424, 8.820231756147395)
    this.renderer.setClearColor(0x191919, 1)
    let ambientLight = new THREE.AmbientLight(0xffffff)
    this.scene.add(ambientLight)
    this.mainMap = {}
    this.assetsManager = new AssetsManager(this, assets, {
      onProgress: (current, total) => {
        console.log(current, total)
      },
      onComplete: () => {
        console.log('加载完成', this.assetsManager)
        this.start()
      },
    })
  }
  start() {
    super.start()
    this.helperTools()
    this.create()
    // this.animator.add(() => {
    //   console.log(this.camera.position)
    // })
  }
  /**
   * 开启辅助工具
   */
  helperTools() {
    // 内存监测
    let state = new State(this)
    state.join()
    // console.log(State)
    // 轨道控制器
    let orbit = new OrbitControls(this)
    this.orbitControls.target = new THREE.Vector3(...center(), 0)
    orbit.join()
    // 坐标轴辅助
    let axes = new THREE.AxesHelper(0)
    axes.position.set(...center(), 0)
    this.scene.add(axes)
  }
  create() {
    // 添加雾
    this.scene.fog = new THREE.Fog(0x191919, 30, 70)
    this.getCenterPoint()
    this.createPlane()
    this.createChinaMap()
    this.createProvinceMap()
    this.createCityMap()
    this.createGrid()
    this.createLight()
    this.createRotateBorder()
    this.createLabel()
    this.createWall()
    this.createBar()
    this.createParticles()
  }
  // 获取中心点位置
  getCenterPoint() {
    // 如果没得cityName，取省名称和数据
    let cityName = config.cityName ? config.cityName : config.provinceName
    let data = config.cityName
      ? transfromGeoJSON(this.assetsManager.loadedItems.province)
      : transfromGeoJSON(this.assetsManager.loadedItems.china)
    let cityData = data.features.filter(item => item.properties.name === cityName)
    if (cityData.length) {
      this.mainMap.center = cityData[0].properties.centroid || [0, 0]
      localStorage.setItem('center', JSON.stringify(this.mainMap.center))
    }
  }
  createGrid() {
    // 添加网格
    const { x, y } = this.mainMap.box.size
    const size = Math.max(x, y) * 5
    let grid = new Grid(this, { size, position: new THREE.Vector3(...center(), 0) })
    grid.gridGroup.rotateX(Math.PI / 2)
    grid.join()
  }
  createChinaMap() {
    try {
      let china = new BaseMap(this, {
        data: this.assetsManager.loadedItems.china,
        topFaceMaterial: new THREE.MeshBasicMaterial({
          color: 0x18263b,
          transparent: true,
          opacity: 0.2,
        }),
        // topFaceMaterial: shaderMaterial.getMaterial(),
        sideMaterial: new THREE.MeshBasicMaterial({
          color: 0x000000,
          transparent: true,
          opacity: 1,
        }),
        renderOrder: 2,
      })
      china.join()
      let chinaLine = new Line(this, {
        data: this.assetsManager.loadedItems.china,
        material: new THREE.LineBasicMaterial({ color: 0x6393bd, depthTest: false }),
        renderOrder: 5,
      })
      chinaLine.join()
      chinaLine.lineGroup.position.z += 0.31
    } catch (error) {
      console.log(error)
    }
  }
  createProvinceMap() {
    let province = new BaseMap(this, {
      data: this.assetsManager.loadedItems.province,
      topFaceMaterial: new THREE.MeshBasicMaterial({
        color: 0x18263b,
        transparent: true,
        opacity: 0.2,
        // depthTest: false,
      }),
      sideMaterial: new THREE.MeshBasicMaterial({
        color: 0x000000,
        transparent: true,
        opacity: 1,
      }),
      renderOrder: 2,
    })
    province.join()
    let provinceLine = new Line(this, {
      data: this.assetsManager.loadedItems.province,
      material: new THREE.LineBasicMaterial({ color: 0x6393bd }),
      // material: new LineMaterial({ color: 0x6393bd, linewidth: 0.002 }),
      // type: 'Line2',
      renderOrder: 5,
    })
    console.log(LineMaterial)

    provinceLine.join()
    provinceLine.lineGroup.position.z += 0.32
  }
  createCityMap() {
    try {
      const sideMaterial = new UpShader(this, {
        start: -0.2, // 开始点
        end: 0.6, // 结束点
        height: 0.4, // 光环高度
        maxTime: 6, // 最大时间
        speed: 0.2,
        color: new THREE.Color('#1A64E0'), // 颜色
        material: new THREE.MeshLambertMaterial({
          color: 0x011d4d,
          transparent: true,
          opacity: 1,
        }),
      })

      let data = config.cityName ? this.assetsManager.loadedItems.city : this.assetsManager.loadedItems.province
      // 添加市地图

      let city = new BaseMap(this, {
        data: data,
        // topFaceMaterial: material.getMaterial(),
        topFaceMaterial: new THREE.MeshPhongMaterial({
          color: 0x132e56,
          emissive: 0x072534,
          transparent: true,
          opacity: 1,
        }),
        sideMaterial: sideMaterial.getMaterial(),
        renderOrder: 6,
        depth: config.cityName ? 0.3 : 3,
      })
      city.mapGroup.position.z += 0.1
      this.mainMap.coordinates = city.getCoordinates()
      this.mainMap.box = getBoundingBox(city.mapGroup)
      // console.log('box', getBoundingBox(city.mapGroup))
      city.join()

      let cityLine = new Line(this, {
        data: data,
        material: new THREE.LineBasicMaterial({
          color: 0xffffff,
          // depthWrite: false,
          // depthTest: false,
        }),
        renderOrder: 20,
      })
      cityLine.join()
      cityLine.lineGroup.position.z += 0.81
    } catch (error) {
      console.log(error)
    }
  }
  createLight() {
    const lights = new Lights(this)
    lights.join()
  }
  createRotateBorder() {
    let { size } = this.mainMap.box
    let width = size.x > size.y ? size.x : size.y
    let plane01 = new Plane(this, {
      width: width + 6, //26,
      needRotate: true,
      rotateSpeed: 0.003,
      material: new THREE.MeshBasicMaterial({
        map: this.assetsManager.loadedItems.rotationBorder1,
        transparent: true,
        opacity: 1,
        side: THREE.DoubleSide,
        depthWrite: false,
      }),
      position: new THREE.Vector3(...center(), 0.33),
    })
    plane01.mesh.renderOrder = 6
    plane01.join()
    //
    let plane02 = new Plane(this, {
      width: width + 2,
      needRotate: true,
      rotateSpeed: -0.008,
      material: new THREE.MeshBasicMaterial({
        map: this.assetsManager.loadedItems.rotationBorder2,
        transparent: true,
        opacity: 1,
        side: THREE.DoubleSide,
        depthWrite: false,
      }),
      position: new THREE.Vector3(...center(), 0.34),
    })
    plane02.mesh.renderOrder = 6
    plane02.join()
  }
  // 创建城市标签
  createLabel() {
    this.label2d = new Label2d(this)
    this.mainMap.coordinates = this.mainMap.coordinates.map(item => {
      return {
        ...item,
        value: random(10, 100),
      }
    })
    this.mainMap.coordinates.forEach(item => {
      if (!item.centroid || !item.center) {
        return false
      }
      let [x, y] = geoProjection(item.centroid || item.center)
      this.createLabelItem(item.name, new THREE.Vector3(x, -y, 0.6))
    })
  }
  createLabelItem(name, position, className = 'mapLabel') {
    const label = this.label2d.create(name, className)
    label.show(name, position)
    this.scene.add(label)
  }
  // 创建透明围墙
  createWall() {
    let cityName = config.cityName ? config.cityName : config.provinceName
    let data = config.cityName
      ? transfromGeoJSON(this.assetsManager.loadedItems.province)
      : transfromGeoJSON(this.assetsManager.loadedItems.china)
    // let data = transfromGeoJSON(this.assetsManager.loadedItems.province)
    let fzData = data.features.filter(item => item.properties.name === cityName)
    console.log(data)
    console.log(cityName, fzData)
    let coordinates = []
    fzData[0].geometry.coordinates[0].map(coords => {
      coords.map(cood => {
        let [x, y] = geoProjection(cood)
        coordinates.push(x, -y)
      })
    })
    let wall = new Wall(this, {
      coordinates: coordinates,
      height: 1.2, //高度
      renderOrder: 10,
      material: new THREE.MeshBasicMaterial({
        color: 0x158ef4,
        side: THREE.DoubleSide,
        transparent: true,
        depthTest: false,
        opacity: 0.2,
      }),
    })
    wall.mesh.position.z += 0.81
    wall.join()
  }
  // 创建波纹shader
  createPlane() {
    //

    let shaderMaterial = new SpreadShader(this, {
      radius: 0.0,
      center: new THREE.Vector3(...center(), 0),
      width: 3.0,
      maxTime: 4.0,
      speed: 40.0,
      color: new THREE.Color('#1A64E0'),
      material: new THREE.MeshLambertMaterial({
        color: 0x011d4d,
        transparent: true,
        depthWrite: false,
      }),
    })
    let [x0, y0] = center()
    let geoArr = []
    let cityBox = {
      min: { x: -9.402891159057617, y: -9.644509315490723, z: 0.3000000029802322 },
      max: { x: 12.942660331726074, y: 6.478987216949463, z: 0.799999988079071 },
    }
    for (let i = 0; i < 5000; i++) {
      let x = random(x0 - 50, x0 + 50)
      let y = random(y0 - 50, y0 + 50)
      let z = random(1, 5) / 10
      if (x > cityBox.min.x && x < cityBox.max.x && y > cityBox.min.y && y < cityBox.max.y) {
        continue
      }

      let w = random(1, 20) / 30
      let cubeGeo = new THREE.BoxBufferGeometry(w, w, w)
      cubeGeo.rotateX(THREE.MathUtils.degToRad(random(0, 360)))
      cubeGeo.rotateY(THREE.MathUtils.degToRad(random(0, 360)))
      cubeGeo.rotateZ(THREE.MathUtils.degToRad(random(0, 360)))
      cubeGeo.translate(x, y, z + w)
      geoArr.push(cubeGeo)
    }
    var allGeometry = mergeBufferGeometries(geoArr)

    // var cubeMesh = new THREE.Mesh(allGeometry, new THREE.MeshBasicMaterial({ color: 0xffffff })) //网格模型对象
    var cubeMesh = new THREE.Mesh(allGeometry, shaderMaterial.getMaterial()) //网格模型对象
    cubeMesh.position.set(...center(), 0)
    this.scene.add(cubeMesh)
    const geo = new THREE.PlaneBufferGeometry(1000, 1000)
    const mesh = new THREE.Mesh(geo, shaderMaterial.getMaterial())
    mesh.renderOrder = -5
    this.scene.add(mesh)
  }
  // 创建柱状图
  createBar() {
    const barGroup = new THREE.Group()
    // 最大高度
    const factor = 1.0
    const height = 4.0 * factor
    // 渐变材质
    const material = new GradientShader(this, {
      height: height,
      color1: new THREE.Color('#00ffff'),
      color2: new THREE.Color('#ffffff'),
      material: new THREE.MeshBasicMaterial({
        transparent: true,
        side: THREE.DoubleSide,
        opacity: 1,
      }),
    }).getMaterial()

    // 获取z轴的位置
    let { z } = this.mainMap.box.box3.max
    // value最大值
    let cityArea = _.orderBy(this.mainMap.coordinates, ['value'], ['desc'])
    let max = _.maxBy(this.mainMap.coordinates, function (o) {
      return o.value
    }).value
    // 循环创建bar
    cityArea.map((item, index) => {
      if (!item.centroid || !item.center) {
        return false
      }
      // 网格
      let geoHeight = height * (item.value / max)

      const geo = new THREE.BoxBufferGeometry(0.2 * factor, 0.2 * factor, geoHeight)
      // 上移
      geo.translate(0, 0, geoHeight / 2)
      const mesh = new THREE.Mesh(geo, material)
      let areaBar = mesh
      let [x, y] = geoProjection(item.centroid || item.center)
      areaBar.position.set(x, -y, z)
      barGroup.add(areaBar)
      if (index < 3) {
        this.createLabelItem(
          `<span class="sort">${index + 1}</span> ${item.name} ${item.value}`,
          new THREE.Vector3(x, -y, z + geoHeight + 0.3 * factor),
          'barLabel',
        )
      } else {
        this.createLabelItem(`${item.value}`, new THREE.Vector3(x, -y, z + geoHeight + 0.3 * factor), 'barLabel')
      }
    })
    this.scene.add(barGroup)
  }
  createParticles() {
    const particles = new Particles(this, {
      range: 30, // 范围
      material: new THREE.PointsMaterial({
        map: Particles.createTexture(),
        size: 0.5,
        color: 0x00eeee,
        transparent: true,
        opacity: 1.0,
        depthTest: false,
        depthWrite: false,
        vertexColors: true,
        blending: THREE.AdditiveBlending,
        sizeAttenuation: true,
      }),
    })
    particles.instance.position.set(0, 0, 15)
    particles.join()
    console.log(particles)
  }
  // 导出模型
  exportModel() {
    exportGLTF(this.scene)
  }
  // 导出图片
  exportImage() {
    exportImage(this.renderer, 'map')
  }
}
